/*
 * User: ronma
 * Date: 18/08/2008 
 *
 * Copyright (2005) IDI. All rights reserved.
 * This software is a proprietary information of Israeli Direct Insurance.
 * Created by IntelliJ IDEA. 
 */
package com.idi.maven.plugins.poms;

import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.jfrog.jade.plugins.common.injectable.MvnInjectableMojoSupport;
import org.jfrog.maven.annomojo.annotations.MojoGoal;
import org.jfrog.maven.annomojo.annotations.MojoParameter;
import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.auth.BasicAuthenticationManager;
import org.tmatesoft.svn.core.auth.ISVNAuthenticationManager;
import org.tmatesoft.svn.core.auth.SVNAuthentication;
import org.tmatesoft.svn.core.auth.SVNPasswordAuthentication;
import org.tmatesoft.svn.core.internal.io.dav.DAVRepositoryFactory;
import org.tmatesoft.svn.core.wc.SVNClientManager;
import org.tmatesoft.svn.core.wc.SVNInfo;
import org.tmatesoft.svn.core.wc.SVNRevision;

import java.io.File;
import static java.lang.String.format;
import java.util.Arrays;
import java.util.Date;
import java.util.Properties;

/**
 * configuring this mojo with some (string values of) InjectProperties members results in
 * properties injected into the maven model that uses this plugin (that is the pom.xml)
 *
 * for example, specifing this configuration:
 <plugin>
     <groupId>com.idi.maven.plugins</groupId>
     <artifactId>poms</artifactId>
     <executions>
         <execution>
             <phase>validate</phase>
             <goals>
                 <goal>injectProperties</goal>
             </goals>
             <configuration>
                 <properties>revisionNumber,fullTime</properties>
             </configuration>
         </execution>
     </executions>
 </plugin>
 *
 * makes the properties inject.revisionNumber and inject.timeStamp accessible in the maven model, for example:
 <build>
    <finalName>${artifactId}-${inject.revisionNumber}-${version}</finalName>
 </build>
 *
 */
@MojoGoal("injectProperties")
public class InjectPropertiesMojo extends MvnInjectableMojoSupport {

    @MojoParameter(description = "comma-separated list of properties from the InjectProperties enum")
    private String properties;

    /**
     * these enum's members are specified in the properties parameter, and processed in the execute method
     */
    public enum InjectProperties {
        revisionNumber {
            @Override
            public String generateInjectedValue(InjectPropertiesMojo injectPropertiesMojo) throws MojoExecutionException {
                return getSvnRevisionNumber(getProjectDirectory(injectPropertiesMojo));
            }},

        fullTime {
            @Override
            public String generateInjectedValue(InjectPropertiesMojo injectPropertiesMojo) throws MojoExecutionException {
                return new Date().toString();
            }},

        svnUrl {
            @Override
            public String generateInjectedValue(InjectPropertiesMojo injectPropertiesMojo) throws MojoExecutionException {
                return getSvnUrl(getProjectDirectory(injectPropertiesMojo));
            }};

        public abstract String generateInjectedValue(InjectPropertiesMojo injectPropertiesMojo) throws MojoExecutionException;
    }

    private static final String INJECT_PREFIX = "inject";

    private static SVNClientManager manager;

    public void execute() throws MojoExecutionException, MojoFailureException {
        if (properties==null || properties.length()==0) {
            return;
        }

        String[] propertiesNames = properties.split(",");
        Properties injectedProperties = new Properties();

        for (final String propertyString : propertiesNames) {
            String propertyName = propertyString.trim();

            try {
                InjectProperties injectProperties = InjectProperties.valueOf(propertyName);
                String propertyFullName = format("%s.%s", INJECT_PREFIX, injectProperties.name());
                injectedProperties.put(propertyFullName, injectProperties.generateInjectedValue(this));
            } catch (IllegalArgumentException ex) {
                getLog().error(format("property %s is invalid. please use one of %s", propertyName, Arrays.deepToString(InjectProperties.values())));
            } catch (MojoExecutionException ex) {
                getLog().error(format("an error occured while trying to generate injected value for %s. never the less, continuing quietly...", propertyName),ex);
            }
        }

        //inject
        Properties projectProperties = getProject().getProperties();
        projectProperties.putAll(injectedProperties);

        getLog().info(format("injected properties: %s", injectedProperties.toString()));
    }

    private static SVNClientManager getSvnClientManager() {
        if (manager == null) {
            DAVRepositoryFactory.setup();
            //todo mamo: get real username and password
            ISVNAuthenticationManager authManager = new BasicAuthenticationManager(
                    new SVNAuthentication[]{new SVNPasswordAuthentication("mel", "mel", false/*do NOT store authentication*/)});
            manager = SVNClientManager.newInstance(null, authManager);
        }
        return manager;
    }

    private static String getSvnRevisionNumber(final File file) throws MojoExecutionException {
        try {
        SVNInfo svnInfo = getSvnClientManager().getWCClient().doInfo(file, SVNRevision.WORKING);
        return String.valueOf(svnInfo.getRevision().getNumber());
        } catch (SVNException e) {
            throw new MojoExecutionException(e.getMessage(), e);
        }
    }

    private static String getSvnUrl(File file) throws MojoExecutionException {
        try {
        SVNInfo svnInfo = getSvnClientManager().getWCClient().doInfo(file, SVNRevision.WORKING);
            return String.valueOf(svnInfo.getURL().toDecodedString());
        } catch (SVNException e) {
            throw new MojoExecutionException(e.getMessage(), e);
        }
    }

    private static File getProjectDirectory(InjectPropertiesMojo injectPropertiesMojo) {
        return injectPropertiesMojo.getProject().getFile().getParentFile();
    }
}